package com.sduept.i1.parse;

import com.google.common.io.LittleEndianDataInputStream;
import com.google.common.io.LittleEndianDataOutputStream;
import com.sduept.i1.I1Server;
import com.sduept.i1.model.*;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.ssssssss.magicapi.Const;
import org.tio.core.ChannelContext;
import org.tio.core.Tio;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class Decoder {
	private static Logger logger = LoggerFactory.getLogger(Decoder.class);
	private static String prefix = "/apps/weather/server";

	private static void sendPacket(String deviceId, ChannelContext context, MonitorPacket packet) {
		if (packet == null) {
			logger.error("Decoder.sendPacket: Make Packet Error in Device {}", deviceId);
			return;
		}
		Tio.bSend(context, packet);
	}

	private static byte[] readNBytes(LittleEndianDataInputStream input, int len) throws IOException {
		byte[] b = new byte[len];
		input.read(b);
		return b;
	}

	// 监测数据报
	// 接收 01H
	// 发送 02H
	public static void onMonitorDataPacket(MonitorPacket packet, ChannelContext context) {
		switch (packet.inApdu.msgType) {
		case 0x01:
		// 接收微气象数据 01H-01H
		// 响应 02H-01H
		{
			String componentId;
			int timeStamp;
			float averageWindSpeed10min;
			int averageWindDirection10min;
			float maxWindSpeed, extremeWindSpeed, standardWindSpeed, airTemperature;
			int humidity;
			float airPressure, precipitation, precipitationIntensity;
			int radiationIntensity;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// componentId 17 被监测设备ID
				// timeStamp 4 采集时间
				// averageWindSpeed10min 4 10分钟平均风速 浮点数
				// averageWindDirection10min 2 10分钟平均风向 整数
				// maxWindSpeed 4 最大风速 浮点数
				// extremeWindSpeed 4 极大风速 浮点数
				// standardWindSpeed 4 标准风速 浮点数
				// airTemperature 4 气温 浮点数
				// humidity 2 湿度 整数
				// airPressure 4 气压 浮点数
				// precipitation 4 降雨量 浮点数
				// precipitationIntensity 4 降水强度 浮点数
				// radiationIntensity 2 光辐射强度 整数

				componentId = new String(readNBytes(input, 17));
				timeStamp = input.readInt();
				averageWindSpeed10min = input.readFloat();
				averageWindDirection10min = input.readUnsignedShort();
				maxWindSpeed = input.readFloat();
				extremeWindSpeed = input.readFloat();
				standardWindSpeed = input.readFloat();
				airTemperature = input.readFloat();
				humidity = input.readUnsignedShort();
				airPressure = input.readFloat();
				precipitation = input.readFloat();
				precipitationIntensity = input.readFloat();
				radiationIntensity = input.readUnsignedShort();

				input.close();

				logger.info("Decoder.onMonitorDataPacket case 01: componentId = {}", componentId);
				logger.info("Decoder.onMonitorDataPacket case 01: timeStamp = {}", timeStamp);
				logger.info("Decoder.onMonitorDataPacket case 01: averageWindSpeed10min = {}", averageWindSpeed10min);
				logger.info("Decoder.onMonitorDataPacket case 01: averageWindDirection10min = {}",
						averageWindDirection10min);
				logger.info("Decoder.onMonitorDataPacket case 01: maxWindSpeed = {}", maxWindSpeed);
				logger.info("Decoder.onMonitorDataPacket case 01: extremeWindSpeed = {}", extremeWindSpeed);
				logger.info("Decoder.onMonitorDataPacket case 01: standardWindSpeed = {}", standardWindSpeed);
				logger.info("Decoder.onMonitorDataPacket case 01: airTemperature = {}", airTemperature);
				logger.info("Decoder.onMonitorDataPacket case 01: humidity = {}", humidity);
				logger.info("Decoder.onMonitorDataPacket case 01: airPressure = {}", airPressure);
				logger.info("Decoder.onMonitorDataPacket case 01: precipitation = {}", precipitation);
				logger.info("Decoder.onMonitorDataPacket case 01: precipitationIntensity = {}", precipitationIntensity);
				logger.info("Decoder.onMonitorDataPacket case 01: radiationIntensity = {}", radiationIntensity);
			} catch (IOException e) {
				logger.error("Decoder.onMonitorDataPacket case 01: Data Input Stream Read Error");
				return;
			}

			// dataStatus 1 数据发送状态 FFH成功 00H失败

			packet.outApduQueue.offer(new Apdu(0x02, 0x01, 1, new byte[] { (byte) 0xFF }));

			sendPacket(packet.identification, context, packet);

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("componentId", componentId);
			params.put("averageWindSpeed10min", averageWindSpeed10min);
			params.put("averageWindDirection10min", averageWindDirection10min);
			params.put("maxWindSpeed", maxWindSpeed);
			params.put("extremeWindSpeed", extremeWindSpeed);
			params.put("standardWindSpeed", standardWindSpeed);
			params.put("airTemperature", airTemperature);
			params.put("humidity", humidity);
			params.put("airPressure", airPressure);
			params.put("precipitation", precipitation);
			params.put("precipitationIntensity", precipitationIntensity);
			params.put("radiationIntensity", radiationIntensity);

			Const.getService().execute("POST", prefix + "/weather", params);
		}
			break;
		case 0x02:
		// 接收杆塔倾斜数据 01H-02H
		// 响应 02H-02H
		{
			String componentId;
			int timeStamp;
			float inclination, inclinationX, inclinationY, angleX, angleY;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// componentId 17 被监测设备ID
				// timeStamp 4 采集时间
				// inclination 4 倾斜度 浮点数
				// inclinationX 4 顺线倾斜度 浮点数
				// inclinationY 4 横向倾斜度 浮点数
				// angleX 4 顺线倾斜角 浮点数
				// angleY 4 横向倾斜角 浮点数

				componentId = new String(readNBytes(input, 17));
				timeStamp = input.readInt();
				inclination = input.readFloat();
				inclinationX = input.readFloat();
				inclinationY = input.readFloat();
				angleX = input.readFloat();
				angleY = input.readFloat();

				input.close();

				logger.error("Decoder.onMonitorDataPacket case 02: componentId = {}", componentId);
				logger.error("Decoder.onMonitorDataPacket case 02: timeStamp = {}", timeStamp);
				logger.error("Decoder.onMonitorDataPacket case 02: inclination = {}", inclination);
				logger.error("Decoder.onMonitorDataPacket case 02: inclinationX = {}", inclinationX);
				logger.error("Decoder.onMonitorDataPacket case 02: inclinationY = {}", inclinationY);
				logger.error("Decoder.onMonitorDataPacket case 02: angleX = {}", angleX);
				logger.error("Decoder.onMonitorDataPacket case 02: angleY = {}", angleY);
			} catch (IOException e) {
				logger.error("Decoder.onMonitorDataPacket case 02: Data Input Stream Read Error");
				return;
			}

			// dataStatus 1 数据发送状态 FFH成功 00H失败

			packet.outApduQueue.offer(new Apdu(0x02, 0x02, 1, new byte[] { (byte) 0xFF }));

			sendPacket(packet.identification, context, packet);

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("componentId", componentId);
			params.put("timeStamp", timeStamp);
			params.put("inclination", inclination);
			params.put("inclinationX", inclinationX);
			params.put("inclinationY", inclinationY);
			params.put("angleX", angleX);
			params.put("angleY", angleY);

			Const.getService().execute("POST", prefix + "/towerFilt", params);
		}
			break;
		default:
			logger.error("Decoder.onMonitorDataPacket: Unknown msgType {}", packet.inApdu.msgType);
			break;
		}
	}

	// 处理控制响应报文
	// 接收 04H
	public static void onControlResponsePacket(MonitorPacket packet, ChannelContext context) {
		switch (packet.inApdu.msgType) {
		case 0xA1:
		// 接收监测装置时间响应 04H-A1H
		{
			int commandStatus, clockTimeStamp;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// commandStatus 1 数据发送状态 FFH成功 00H失败

				commandStatus = input.readUnsignedByte();
				clockTimeStamp = input.readInt();

				input.close();

				logger.info("Decoder.onControlResponsePacket case A1: commandStatus = {}", commandStatus);
				logger.info("Decoder.onControlResponsePacket case A1: clockTimeStamp = {}", clockTimeStamp);
			} catch (IOException e) {
				logger.error("Decoder.onControlResponsePacket case A1: Data Input Stream Read Error");
				return;
			}

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("commandStatus", commandStatus);
			params.put("clockTimeStamp", clockTimeStamp);

			Const.getService().execute("POST", prefix + "/clockTime", params);
		}
			break;
		case 0xA2:
		// 接收监测装置网络适配器响应 04H-A2H
		{
			int commandStatus, requestSetFlag, requestFlag;
			byte[] ip, subnetMask, gateway, dnsServer, phoneNumber;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// commandStatus 1 数据发送状态 FFH成功 00H失败
				// requestSetFlag 1 参数配置类型标识 00H表示查询，01H表示设置
				// requestFlag 1 标识位，字节自低向高依次对应各选择请求或设置的参数项，1表示选择，0表示未选择
				// ip 4 IP地址
				// subnetMask 4 子网掩码
				// gateway 4 网关
				// dnsServer 4 DNS服务器
				// phoneNumber 20 手机串号

				commandStatus = input.readUnsignedByte();
				requestSetFlag = input.readUnsignedByte();
				requestFlag = input.readUnsignedByte();
				ip = readNBytes(input, 4);
				subnetMask = readNBytes(input, 4);
				gateway = readNBytes(input, 4);
				dnsServer = readNBytes(input, 4);
				phoneNumber = readNBytes(input, 20);

				logger.info("Decoder.onControlResponsePacket case A2: commandStatus = {}", commandStatus);
				logger.info("Decoder.onControlResponsePacket case A2: requestSetFlag = {}", requestSetFlag);
				logger.info("Decoder.onControlResponsePacket case A2: requestFlag = {}", requestFlag);
				logger.info("Decoder.onControlResponsePacket case A2: ip = {}", ip);
				logger.info("Decoder.onControlResponsePacket case A2: subnetMask = {}", subnetMask);
				logger.info("Decoder.onControlResponsePacket case A2: gateway = {}", gateway);
				logger.info("Decoder.onControlResponsePacket case A2: dnsServer = {}", dnsServer);
				logger.info("Decoder.onControlResponsePacket case A2: phoneNumber = {}", phoneNumber);
			} catch (IOException e) {
				logger.error("Decoder.onControlResponsePacket case A2: Data Input Stream Read Error");
				return;
			}

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("commandStatus", commandStatus);
			params.put("requestSetFlag", requestSetFlag);
			params.put("requestFlag", requestFlag);
			params.put("ip", ip);
			params.put("subnetMask", subnetMask);
			params.put("gateway", gateway);
			params.put("dnsServer", dnsServer);
			params.put("phoneNumber", phoneNumber);

			Const.getService().execute("POST", prefix + "/netAdapter", params);
		}
			break;
		case 0xA3:
		// 接收历史数据响应 04H-A3H
		{
			int commandStatus, requestType;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// commandStatus 1 数据发送状态 FFH成功 00H失败
				// requestType 1 请求数据类型

				commandStatus = input.readUnsignedByte();
				requestType = input.readUnsignedByte();

				input.close();

				logger.info("Decoder.onControlResponsePacket case A3: commandStatus = {}", commandStatus);
				logger.info("Decoder.onControlResponsePacket case A3: requestType = {}", requestType);
			} catch (IOException e) {
				logger.error("Decoder.onControlResponsePacket case A3: Data Input Stream Read Error");
				return;
			}

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("commandStatus", commandStatus);
			params.put("requestType", requestType);

			Const.getService().execute("POST", prefix + "/historyData", params);
		}
			break;
		case 0xA4:
		// 接收心跳采集参数响应 04H-A4H
		{
			int commandStatus, requestType, requestFlag;
			int mainTime, sampleCount, sampleFrequency, heartbeatTime;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// commandStatus 1 数据发送状态 FFH成功 00H失败
				// requestType 1 配置的参数类型
				// requestFlag 1 标识位，字节自低向高依次对应各选择请求或设置的参数项
				// mainTime 2 设定后的采集时间周期
				// sampleCount 2 设定后的高速采样点数
				// sampleFrequency 2 设定后高速采样频率
				// heartbeatTime 1 心跳上送周期

				commandStatus = input.readUnsignedByte();
				requestType = input.readUnsignedByte();
				requestFlag = input.readUnsignedByte();
				mainTime = input.readUnsignedShort();
				sampleCount = input.readUnsignedShort();
				sampleFrequency = input.readUnsignedShort();
				heartbeatTime = input.readUnsignedByte();

				input.close();

				logger.info("Decoder.onControlResponsePacket case A4: commandStatus = {}", commandStatus);
				logger.info("Decoder.onControlResponsePacket case A4: requestType = {}", requestType);
				logger.info("Decoder.onControlResponsePacket case A4: requestFlag = {}", requestFlag);
				logger.info("Decoder.onControlResponsePacket case A4: mainTime = {}", mainTime);
				logger.info("Decoder.onControlResponsePacket case A4: sampleCount = {}", sampleCount);
				logger.info("Decoder.onControlResponsePacket case A4: sampleFrequency = {}", sampleFrequency);
				logger.info("Decoder.onControlResponsePacket case A4: heartbeatTime = {}", heartbeatTime);
			} catch (IOException e) {
				logger.error("Decoder.onControlResponsePacket case A4: Data Input Stream Read Error");
				return;
			}

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("commandStatus", commandStatus);
			params.put("requestType", requestType);
			params.put("requestFlag", requestFlag);
			params.put("mainTime", mainTime);
			params.put("sampleCount", sampleCount);
			params.put("sampleFrequency", sampleFrequency);
			params.put("heartbeatTime", heartbeatTime);

			Const.getService().execute("POST", prefix + "/collectPeriod", params);
		}
			break;
		case 0xA5:
		// 接收模型参数配置信息响应 04H-A5H
		{
			int commandStatus, requestSetFlag, configTotal;
			String[] configNames;
			int[] configDataTypes, configDatas;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// commandStatus 1 数据发送状态 FFH成功 00H失败
				// requestSetFlag 1 参数配置类型标识 00H查询配置信息 01H设置配置信息
				// configTotal 1 配置参数个数
				// configName_i 6 第i个配置参数的名称
				// configDataType_i 1 第i个配置参数的数据类型
				// configData_i 4 第i个配置参数的值

				commandStatus = input.readUnsignedByte();
				requestSetFlag = input.readUnsignedByte();
				configTotal = input.readUnsignedByte();
				configNames = new String[configTotal];
				configDataTypes = new int[configTotal];
				configDatas = new int[configTotal];
				for (int i = 0; i < configTotal; i++) {
					configNames[i] = new String(readNBytes(input, 6));
					configDataTypes[i] = input.readUnsignedByte();
					configDatas[i] = input.readInt();
				}

				input.close();

				logger.info("Decoder.onControlResponsePacket case A5: commandStatus = {}", commandStatus);
				logger.info("Decoder.onControlResponsePacket case A5: requestSetFlag = {}", requestSetFlag);
				logger.info("Decoder.onControlResponsePacket case A5: configTotal = {}", configTotal);
				logger.info("Decoder.onControlResponsePacket case A5: configNames = {}", configNames.toString());
				logger.info("Decoder.onControlResponsePacket case A5: configDataTypes = {}",
						configDataTypes.toString());
				logger.info("Decoder.onControlResponsePacket case A5: configDatas = {}", configDatas.toString());
			} catch (IOException e) {
				logger.error("Decoder.onControlResponsePacket case A5: Data Input Stream Read Error");
				return;
			}

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("commandStatus", commandStatus);
			params.put("requestSetFlag", requestSetFlag);
			params.put("configTotal", configTotal);
			params.put("configNames", configNames);
			params.put("configDataTypes", configDataTypes);
			params.put("configDatas", configDatas);

			Const.getService().execute("POST", prefix + "/paramConfig", params);
		}
			break;
		case 0xA6:
		// 接收报警阈值响应 04H-06H
		{
			int commandStatus, requestType, alarmTotal;
			String[] alarmParaInfo;
			int[] alarmParaValue;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// commandStatus 1 数据发送状态 FFH成功 00H失败
				// requestType 1 配置的参数类型
				// alarmTotal 1 报警参数个数
				// alarmPara 10N 报警参数信息6+参数值4

				commandStatus = input.readUnsignedByte();
				requestType = input.readUnsignedByte();
				alarmTotal = input.readUnsignedByte();
				alarmParaInfo = new String[alarmTotal];
				alarmParaValue = new int[alarmTotal];
				for (int i = 0; i < alarmTotal; i++) {
					alarmParaInfo[i] = new String(readNBytes(input, 6));
					alarmParaValue[i] = input.readInt();
				}

				input.close();

				logger.info("Decoder.onControlResponsePacket case A6: commandStatus = {}", commandStatus);
				logger.info("Decoder.onControlResponsePacket case A6: requestType = {}", requestType);
				logger.info("Decoder.onControlResponsePacket case A6: alarmTotal = {}", alarmTotal);
				logger.info("Decoder.onControlResponsePacket case A6: alarmParaInfo = {}", alarmParaInfo.toString());
				logger.info("Decoder.onControlResponsePacket case A6: alarmParaValue = {}", alarmParaValue.toString());
			} catch (IOException e) {
				logger.error("Decoder.onControlResponsePacket case A6: Data Input Stream Read Error");
				return;
			}

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("commandStatus", commandStatus);
			params.put("requestType", requestType);
			params.put("alarmTotal", alarmTotal);
			params.put("alarmParaInfo", alarmParaInfo);
			params.put("alarmParaValue", alarmParaValue);

			Const.getService().execute("POST", prefix + "/alarmThreshold", params);
		}
			break;
		case 0xA7:
		// 接收指向上位机信息响应 04H-07H
		{
			int commandStatus, requestFlag, port;
			byte[] ipAddress, domainName;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// commandStatus 1 数据发送状态 FFH成功 00H失败
				// requestFlag 1 标识位，字节位自低向高依次对应各选择请求或设置的参数项
				// ipAddress 4 主站系统ip地址
				// port 2 主站系统端口号
				// domainName 64 主站系统域名，以\0结尾的ASCII字符串

				commandStatus = input.readUnsignedByte();
				requestFlag = input.readUnsignedByte();
				ipAddress = readNBytes(input, 4);
				port = input.readUnsignedShort();
				domainName = readNBytes(input, 64);

				input.close();

				logger.info("Decoder.onControlResponsePacket case A7: commandStatus = {}", commandStatus);
				logger.info("Decoder.onControlResponsePacket case A7: requestFlag = {}", requestFlag);
				logger.info("Decoder.onControlResponsePacket case A7: ipAddress = {}", ipAddress);
				logger.info("Decoder.onControlResponsePacket case A7: port = {}", port);
				logger.info("Decoder.onControlResponsePacket case A7: domainName = {}", domainName);
			} catch (IOException e) {
				logger.error("Decoder.onControlResponsePacket case A7: Data Input Stream Read Error");
				return;
			}

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("commandStatus", commandStatus);
			params.put("requestFlag", requestFlag);
			params.put("ipAddress", ipAddress);
			params.put("port", port);
			params.put("domainName", domainName);

			Const.getService().execute("POST", prefix + "/devicePoint", params);
		}
			break;
		case 0xA8:
		// 接收基本信息响应 04H-A8H
		{
			int commandStatus, requestType, infoType;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// commandStatus 1 数据发送状态 FFH成功 00H失败
				// requestType 1 配置的参数类型
				// infoType 1 信息类型 01H基本信息 02H状态信息

				commandStatus = input.readUnsignedByte();
				requestType = input.readUnsignedByte();
				infoType = input.readUnsignedByte();

				input.close();

				logger.info("Decoder.onControlResponsePacket case A8: commandStatus = {}", commandStatus);
				logger.info("Decoder.onControlResponsePacket case A8: requestType = {}", requestType);
				logger.info("Decoder.onControlResponsePacket case A8: infoType = {}", infoType);
			} catch (IOException e) {
				logger.error("Decoder.onControlResponsePacket case A8: Data Input Stream Read Error");
				return;
			}

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("commandStatus", commandStatus);
			params.put("requestType", requestType);
			params.put("infoType", infoType);

			Const.getService().execute("POST", prefix + "/infoType", params);
		}
			break;
		case 0xAA:
		// 接收远程升级结束标记响应 04H-AAH
		{
			I1Server.clientManagement.setResponse(packet.identification);
		}
			break;
		case 0xAB:
		// 接收远程升级补包请求 04H-ABH
		{
			byte[] fileName;
			int complementPackSum;
			int[] sComplementPackNo;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// fileName 20 文件名，以'\0'结尾ASCII字符串，占用20字符
				// complementPackSum 4 补包包数-未收到的总包数
				// sComplementPackNo 4N 补包包号序列

				fileName = readNBytes(input, 20);
				complementPackSum = input.readInt();
				sComplementPackNo = new int[complementPackSum];
				for (int i = 0; i < complementPackSum; i++) {
					sComplementPackNo[i] = input.readInt();
				}

				input.close();

				logger.info("Decoder.onControlResponsePacket case AB: fileName = {}", fileName.toString());
				logger.info("Decoder.onControlResponsePacket case AB: complementPackSum = {}", complementPackSum);
				logger.info("Decoder.onControlResponsePacket case AB: sComplementPackNo = {}",
						sComplementPackNo.toString());
			} catch (IOException e) {
				logger.error("Decoder.onControlResponsePacket case AB: Data Input Stream Read Error");
				return;
			}

			int endByte = 0;
			while (endByte < 20) {
				if (fileName[endByte] == '\0') {
					break;
				}
				endByte++;
			}

			if (endByte == 20) {
				logger.error("Decoder.onControlResponsePacket case AB: File Name Format Error");
				return;
			}

			String fileNameStr = new String(fileName).substring(0, endByte);

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("fileName", fileNameStr);
			params.put("complementPackSum", complementPackSum);
			params.put("sComplementPackNo", sComplementPackNo);

			Const.getService().execute("POST", prefix + "/upgradeSuccess", params);

			// 判断是否需要补包
			if (complementPackSum == 0) {
				return;
			}

			I1Server.remoteUpgradeComplement(packet.identification, fileNameStr, sComplementPackNo);
		}
			break;
		case 0xAC:
		// 接收监测装置ID响应 04H-ACH
		{
			int commandStatus, requestFlag;
			String newCmdId, componentId, originalId;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// commandStatus 1 数据发送状态 FFH成功 00H失败
				// requestFlag 1 标识位，字节位自低向高依次对应各选择请求或设置的参数项
				// newCmdId 17 状态监测装置新设置的ID
				// componentId 17 被监测设备新设置的ID
				// originalId 17 原始ID

				commandStatus = input.readUnsignedByte();
				requestFlag = input.readUnsignedByte();
				newCmdId = new String(readNBytes(input, 17));
				componentId = new String(readNBytes(input, 17));
				originalId = new String(readNBytes(input, 17));

				input.close();

				logger.info("Decoder.onControlResponsePacket case AC: commandStatus = {}", commandStatus);
				logger.info("Decoder.onControlResponsePacket case AC: requestFlag = {}", requestFlag);
				logger.info("Decoder.onControlResponsePacket case AC: newCmdId = {}", newCmdId.toString());
				logger.info("Decoder.onControlResponsePacket case AC: componentId = {}", componentId.toString());
				logger.info("Decoder.onControlResponsePacket case AC: originalId = {}", originalId.toString());
			} catch (IOException e) {
				logger.error("Decoder.onControlResponsePacket case AC: Data Input Stream Read Error");
				return;
			}

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("commandStatus", commandStatus);
			params.put("requestFlag", requestFlag);
			params.put("newCmdId", newCmdId);
			params.put("componentId", componentId);
			params.put("originalId", originalId);

			Const.getService().execute("POST", prefix + "/deviceId", params);
		}
			break;
		case 0xAD:
		// 接收装置复位响应 04H-ADH
		{
			int commandStatus;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// commandStatus 1 数据发送状态 FFH成功 00H失败

				commandStatus = input.readUnsignedByte();
				input.close();

				logger.info("Decoder.onControlResponsePacket case AD: commandStatus = {}", commandStatus);
			} catch (IOException e) {
				logger.error("Decoder.onControlResponsePacket case AD: Data Input Stream Read Error");
				return;
			}

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("commandStatus", commandStatus);

			Const.getService().execute("POST", prefix + "/reset", params);
		}
			break;
		case 0xAE:
		// 接收装置苏醒时间响应 04H-AEH
		{
			int commandStatus;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// commandStatus 1 数据发送状态 FFH成功 00H失败

				commandStatus = input.readUnsignedByte();
				input.close();

				logger.info("Decoder.onControlResponsePacket case AE: commandStatus = {}", commandStatus);
			} catch (IOException e) {
				logger.error("Decoder.onControlResponsePacket case AE: Data Input Stream Read Error");
				return;
			}

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("commandStatus", commandStatus);

			Const.getService().execute("POST", prefix + "/awakeTime", params);
		}
			break;
		case 0xB8:
		// 接收远程升级响应 04H-B8H
		{
			int upgradeStatus;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// upgradeStatus 1 装置响应升级请求 FFH成功 00H失败 01H~FEH其他

				upgradeStatus = input.readUnsignedByte();
				input.close();

				logger.info("Decoder.onControlResponsePacket case B8: upgradeStatus = {}", upgradeStatus);
			} catch (IOException e) {
				logger.error("Decoder.onControlResponsePacket case B8: Data Input Stream Read Error");
				return;
			}

			if (upgradeStatus == 0xFF) {
				String deviceId = packet.identification;
				I1Server.remoteUpgrade(deviceId, RemoteUpgradeData.fileName);
			}
		}
			break;
		case 0xB9:
		// 接收声光语音广播喊话启停响应 03H-B9H
		{
			int functionType, commandStatus, control;
			byte[] reserve;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// functionType 2 功能分类 01H声光告警 02HWiFi功能 其他
				// commandStatus 1 状态 FFH成功 00H失败
				// control 1 00H停用 01H启用
				// reserve 8 备用

				functionType = input.readUnsignedShort();
				commandStatus = input.readUnsignedByte();
				control = input.readUnsignedByte();
				reserve = readNBytes(input, 8);

				input.close();

				logger.info("Decoder.onControlResponsePacket case B9: functionType = {}", functionType);
				logger.info("Decoder.onControlResponsePacket case B9: commandStatus = {}", commandStatus);
				logger.info("Decoder.onControlResponsePacket case B9: control = {}", control);
				logger.info("Decoder.onControlResponsePacket case B9: reserve = {}", reserve.toString());
			} catch (IOException e) {
				logger.error("Decoder.onControlResponsePacket case B9: Data Input Stream Read Error");
				return;
			}

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("functionType", functionType);
			params.put("commandStatus", commandStatus);
			params.put("control", control);
			params.put("reserve", reserve);

			Const.getService().execute("POST", prefix + "/functionControl", params);
		}
			break;
		case 0xBA:
		// 接收http升级文件推送响应 04H-BAH
		{
			int commandStatus = 0;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// commandStatus 1 数据发送状态 FFH成功 00H失败

				commandStatus = input.readUnsignedByte();
				input.close();

				logger.info("Decoder.onControlResponsePacket case BA: commandStatus = {}", commandStatus);
			} catch (IOException e) {
				logger.error("Decoder.onControlResponsePacket case BA: Data Input Stream Read Error");
				return;
			}

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("commandStatus", commandStatus);

			Const.getService().execute("POST", prefix + "/httpUpgradePush", params);
		}
			break;
		case 0xBB:
		// 接收摄像机3D控球调节响应 04H-BBH
		{
			int commandStatus = 0;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// commandStatus 1 数据发送状态 FFH成功 00H失败

				commandStatus = input.readUnsignedByte();
				input.close();

				logger.info("Decoder.onControlResponsePacket case BB: commandStatus = {}", commandStatus);
			} catch (IOException e) {
				logger.error("Decoder.onControlResponsePacket case BB: Data Input Stream Read Error");
				return;
			}

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("commandStatus", commandStatus);

			Const.getService().execute("POST", prefix + "/3DBallControl", params);
		}
		case 0xBC:
		// 接收到摄像机巡检配置响应 04H-BCH
		{
			int channelNo = 0, commandStatus = 0;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// channnelNo 1 通道号（从 1 开始）
				// commandStatus 1 数据发送状态 FFH成功 00H失败

				channelNo = input.readUnsignedByte();
				commandStatus = input.readUnsignedByte();

				input.close();

				logger.info("Decoder.onControlResponsePacket case BC: channelNo = {}", channelNo);
				logger.info("Decoder.onControlResponsePacket case BC: commandStatus = {}", commandStatus);
			} catch (IOException e) {
				logger.error("Decoder.onControlResponsePacket case BC: Data Input Stream Read Error");
				return;
			}

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("channelNo", channelNo);
			params.put("commandStatus", commandStatus);

			Const.getService().execute("POST", prefix + "/cameraCruiseSet", params);
		}
			break;
		case 0xBD:
		// 接收到摄像机巡检查询响应 04H-BDH
		{
			int channelNo, commandStatus, cruiseCount;
			int[] cruiseNos, pointerCounts;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// channelNo 1 通道号
				// commandStatus 1 数据发送状态 FFH成功 00H失败
				// cruiseCount 1 巡检组数目
				// cruiseNo_i 1 巡检组号
				// pointCount_i 1 巡检点数目

				channelNo = input.readUnsignedByte();
				commandStatus = input.readUnsignedByte();
				cruiseCount = input.readUnsignedByte();
				cruiseNos = new int[cruiseCount];
				pointerCounts = new int[cruiseCount];
				for (int i = 0; i < commandStatus; i++) {
					cruiseNos[i] = input.readUnsignedByte();
					pointerCounts[i] = input.readUnsignedByte();
				}

				input.close();

				logger.info("Decoder.onControlResponsePacket case BD: channelNo = {}", channelNo);
				logger.info("Decoder.onControlResponsePacket case BD: commandStatus = {}", commandStatus);
				logger.info("Decoder.onControlResponsePacket case BD: cruiseCount = {}", cruiseCount);
				logger.info("Decoder.onControlResponsePacket case BD: cruiseNos = {}", cruiseNos.toString());
				logger.info("Decoder.onControlResponsePacket case BD: pointerCounts = {}", pointerCounts.toString());
			} catch (IOException e) {
				logger.error("Decoder.onControlResponsePacket case BD: Data Input Stream Read Error");
				return;
			}

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("channelNo", channelNo);
			params.put("commandStatus", commandStatus);
			params.put("cruiseCount", cruiseCount);
			params.put("cruiseNos", cruiseNos);
			params.put("pointerCounts", pointerCounts);

			Const.getService().execute("POST", prefix + "/cameraCruiseGet", params);
		}
			break;
		case 0xBE:
		// 接收摄影机巡检策略查询与设置响应 04H-BEH
		{
			int channelNo, requestSetFlag, commandStatus, configNum;
			int[] enables, cruiseNos, cruiseNums, startYears, startMonths, startDays;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// channelNo 1 通道号
				// requestSetFlag 1 参数配置类型标识 00H查询 01H设置
				// commandStatus 1 数据发送状态 FFH成功 00H失败
				// configNum 1 线路巡检配置数目
				// enable_i 1 巡检使能标志
				// cruiseNo_i 1 巡检组号
				// cruiseNum_i 1 巡检次数
				// cruiseStartTime_i 3 开始时间 年/月/日

				channelNo = input.readUnsignedByte();
				requestSetFlag = input.readUnsignedByte();
				commandStatus = input.readUnsignedByte();
				configNum = input.readUnsignedByte();
				enables = new int[configNum];
				cruiseNos = new int[configNum];
				cruiseNums = new int[configNum];
				startYears = new int[configNum];
				startMonths = new int[configNum];
				startDays = new int[configNum];
				for (int i = 0; i < configNum; i++) {
					enables[i] = input.readUnsignedByte();
					cruiseNos[i] = input.readUnsignedByte();
					cruiseNums[i] = input.readUnsignedByte();
					startYears[i] = input.readUnsignedByte();
					startMonths[i] = input.readUnsignedByte();
					startDays[i] = input.readUnsignedByte();
				}

				input.close();

				logger.info("Decoder.onControlResponsePacket case BE: channelNo = {}", channelNo);
				logger.info("Decoder.onControlResponsePacket case BE: requestSetFlag = {}", requestSetFlag);
				logger.info("Decoder.onControlResponsePacket case BE: commandStatus = {}", commandStatus);
				logger.info("Decoder.onControlResponsePacket case BE: configNum = {}", configNum);
				logger.info("Decoder.onControlResponsePacket case BE: enables = {}", enables.toString());
				logger.info("Decoder.onControlResponsePacket case BE: cruiseNos = {}", cruiseNos.toString());
				logger.info("Decoder.onControlResponsePacket case BE: cruiseNums = {}", cruiseNums.toString());
				logger.info("Decoder.onControlResponsePacket case BE: startYears = {}", startYears.toString());
				logger.info("Decoder.onControlResponsePacket case BE: startMonths = {}", startMonths.toString());
				logger.info("Decoder.onControlResponsePacket case BE: startDays = {}", startDays.toString());
			} catch (IOException e) {
				logger.error("Decoder.onControlResponsePacket case BE: Data Input Stream Read Error");
				return;
			}

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("channelNo", channelNo);
			params.put("requestSetFlag", requestSetFlag);
			params.put("commandStatus", commandStatus);
			params.put("configNum", configNum);
			params.put("enables", enables);
			params.put("cruiseNos", cruiseNos);
			params.put("cruiseNums", cruiseNums);
			params.put("startYears", startYears);
			params.put("startMonths", startMonths);
			params.put("startDays", startDays);

			Const.getService().execute("POST", prefix + "/cameraCruiseStrategy", params);
		}
			break;
		default:
			logger.error("Decoder.onControlResponsePacket: Unknown msgType {}", packet.inApdu.msgType);
			break;
		}
	}

	// 远程图像数据报
	// 接收 05H
	// 发送 06H
	public static void onRemoteImageDataPacket(MonitorPacket packet, ChannelContext context) {

		switch (packet.inApdu.msgType) {
		case 0xEF:
		// 收到上送图像/短视频请求 05H EFH
		// 响应 06H EFH
		{
			int channelNo, packetHigh, packetLow, imageId;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// channel 1 通道号
				// packetHigh 1 包数高位
				// packetLow 1 包数低位
				// imageId 4 内容ID
				// reserve 4 备用

				channelNo = input.readByte();
				packetHigh = input.readByte();
				packetLow = input.readByte();
				imageId = input.readInt();

				input.close();

				logger.info("Encoder.onRemoteImageDataPacket case 0xEF: channelNo = {}", channelNo);
				logger.info("Encoder.onRemoteImageDataPacket case 0xEF: packetHigh = {}", packetHigh);
				logger.info("Encoder.onRemoteImageDataPacket case 0xEF: packetLow = {}", packetLow);
				logger.info("Encoder.onRemoteImageDataPacket case 0xEF: imageId = {}", imageId);
			} catch (IOException e) {
				logger.error("Encoder.onRemoteImageDataPacket case 0xEF: Data Input Stream Read Error");
				return;
			}

			I1Server.imageStorageManagement.createImageStorage(packet.identification, channelNo, imageId,
					packetHigh << 8 + packetLow);

			// Upload_Status 1 允许：FFH 不允许：00H

			packet.outApduQueue.offer(new Apdu(0x06, 0xEF, 1, new byte[] { (byte) 0xFF }));

			sendPacket(packet.identification, context, packet);

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("channelNo", channelNo);
			params.put("packetHigh", packetHigh);
			params.put("packetLow", packetLow);
			params.put("imageId", imageId);

			Const.getService().execute("POST", prefix + "/imageRequest", params);
		}
			break;
		case 0xF0:
		// 收到图像数据 05H F0H
		// 不响应
		{
			int channelNo, packetNo, subpacketNo, imageId, imageOffset;
			byte[] imageData;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// channelNo 1 通道号
				// packetNo 2 总包数
				// subpacketNo 2 子包包号
				// imageId 4 图像ID
				// imageOffset 4 图像偏移
				// imageData N 图像数据

				channelNo = input.readUnsignedByte();
				packetNo = input.readUnsignedShort();
				subpacketNo = input.readUnsignedShort();
				imageId = input.readInt();
				imageOffset = input.readInt();
				imageData = readNBytes(input, packet.inApdu.elements.length - 13);

				input.close();

				logger.info("Encoder.onRemoteImageDataPacket case 0xF0: channelNo = {}", channelNo);
				logger.info("Encoder.onRemoteImageDataPacket case 0xF0: packetNo = {}", packetNo);
				logger.info("Encoder.onRemoteImageDataPacket case 0xF0: subpacketNo = {}", subpacketNo);
				logger.info("Encoder.onRemoteImageDataPacket case 0xF0: imageId = {}", imageId);
				logger.info("Encoder.onRemoteImageDataPacket case 0xF0: imageOffset = {}", imageOffset);
				logger.info("Encoder.onRemoteImageDataPacket case 0xF0: imageData = {}", imageData);
			} catch (IOException e) {
				logger.error("Encoder.onRemoteImageDataPacket case 0xF0: Data Input Stream Read Error");
				return;
			}

			I1Server.imageStorageManagement.storePacket(packet.identification, channelNo, subpacketNo, imageData);

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("channelNo", channelNo);
			params.put("packetNo", packetNo);
			params.put("subpacketNo", subpacketNo);
			params.put("imageId", imageId);
			params.put("imageOffset", imageOffset);
			params.put("imageData", imageData);

			Const.getService().execute("POST", prefix + "/imageData", params);
		}
			break;
		case 0xF1:
		// 收到图像数据上送结束标记报文 05H F1H
		// 返回未收到的包号 06H F2H
		{
			int channelNo, timeStamp, fileType;
			byte[] md5;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// channelNo 1 通道号
				// timeStamp 4 本图像/视频拍摄时间
				// md5 32 文件MD5码
				// fileType 1 文件类型
				// reserve 7 备用

				channelNo = input.readByte();
				timeStamp = input.readInt();
				md5 = readNBytes(input, 32);
				fileType = input.readByte();

				input.close();

				logger.info("Encoder.onRemoteImageDataPacket case 0xF1: channelNo = {}", channelNo);
				logger.info("Encoder.onRemoteImageDataPacket case 0xF1: timeStamp = {}", timeStamp);
				logger.info("Encoder.onRemoteImageDataPacket case 0xF1: md5 = {}", md5.toString());
				logger.info("Encoder.onRemoteImageDataPacket case 0xF1: fileType = {}", fileType);
			} catch (IOException e) {
				logger.error("Encoder.onRemoteImageDataPacket case 0xF1: Data Input Stream Read Error");
				return;
			}

			// 将未收到的包号通过该命令下发给监拍装置
			int[] lostSubpacketNos = I1Server.imageStorageManagement.getLostSubpacketNos(packet.identification,
					channelNo);
			int lostNum = lostSubpacketNos.length;
			int imageId = I1Server.imageStorageManagement.getImageId(packet.identification, channelNo);

			int msgLen = 11 + lostNum * 2;
			ByteArrayOutputStream byteStream = new ByteArrayOutputStream(msgLen);
			LittleEndianDataOutputStream output = new LittleEndianDataOutputStream(byteStream);

			try {
				// channelNo 1 通道号
				// complementPackSum 2 补包包数，未收到的总包数
				// complementPackNo 2n 补包包号序列
				// imageId 4 内容id
				// reserve 4 备用

				output.writeByte(channelNo);
				output.writeShort(lostNum);
				for (int i = 0; i < lostNum; i++) {
					output.writeShort(lostSubpacketNos[i]);
				}
				output.writeInt(imageId);
				output.write(new byte[4]);

				output.close();
			} catch (IOException e) {
				logger.error("Encoder.onRemoteImageDataPacket case 0xF1: Data Output Stream Write Error");
				return;
			}

			packet.outApduQueue.offer(new Apdu(0x06, 0xF2, msgLen, byteStream.toByteArray()));
			sendPacket(packet.identification, context, packet);

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("channelNo", channelNo);
			params.put("timeStamp", timeStamp);
			params.put("md5", md5);
			params.put("fileType", fileType);

			Const.getService().execute("POST", prefix + "/imageDataEnd", params);
		}

			break;
		default:
			logger.error("Encoder.onRemoteImageDataPacket: Unknown msgType {}", packet.inApdu.msgType);
			break;
		}
	}

	// 服务端使用
	// 接收图像控制响应报 08H
	public static void onImageControlResponsePacket(MonitorPacket packet, ChannelContext context) {
		switch (packet.inApdu.msgType) {
		case 0xD0:
		// 接收摄像头远程调节响应 08H-D0H
		{
			int commandStatus;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// commandStatus 1 数据发送状态 FFH成功 00H失败

				commandStatus = input.readUnsignedByte();
				input.close();

				logger.info("Encoder.onImageControlResponsePacket case 0xD0: commandStatus = {}", commandStatus);
			} catch (IOException e) {
				logger.error("Encoder.onImageControlResponsePacket case 0xD0: Data Input Stream Read Error");
				return;
			}

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("commandStatus", commandStatus);

			Const.getService().execute("POST", prefix + "/cameraControl", params);
		}
			break;
		case 0xEB:
		// 收到图像参数响应 08H-EBH
		{
			int commandStatus, requestSetFlag, requestFlag;
			int colorSelect, resolution, luminance, contrast, saturation;
			int channelNo, preset;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// commandStatus 1 数据发送状态 FFH成功 00H失败
				// requestSetFlag 1 参数配置类型标识 00H查询配置信息 01H设置配置信息
				// requestFlag 1 标识位，字节位由低向高依次对应各项选择项请求或设置的参数项
				// colorSelect 1 色彩选择 0黑白 1彩色
				// resolution 1 自定义图像分辨率
				// luminance 1 亮度
				// contrast 1 对比度
				// saturation 1 饱和度
				// channelNo 1 通道号
				// preset 1 预置位
				// reserve 6 备用

				commandStatus = input.readByte();
				requestSetFlag = input.readByte();
				requestFlag = input.readByte();
				colorSelect = input.readByte();
				resolution = input.readByte();
				luminance = input.readByte();
				contrast = input.readByte();
				saturation = input.readByte();
				channelNo = input.readByte();
				preset = input.readByte();

				input.close();

				logger.info("Decoder.onImageControlResponsePacket case EB: commandStatus = {}", commandStatus);
				logger.info("Decoder.onImageControlResponsePacket case EB: requestSetFlag = {}", requestSetFlag);
				logger.info("Decoder.onImageControlResponsePacket case EB: requestFlag = {}", requestFlag);
				logger.info("Decoder.onImageControlResponsePacket case EB: colorSelect = {}", colorSelect);
				logger.info("Decoder.onImageControlResponsePacket case EB: resolution = {}", resolution);
				logger.info("Decoder.onImageControlResponsePacket case EB: luminance = {}", luminance);
				logger.info("Decoder.onImageControlResponsePacket case EB: contrast = {}", contrast);
				logger.info("Decoder.onImageControlResponsePacket case EB: saturation = {}", saturation);
				logger.info("Decoder.onImageControlResponsePacket case EB: channelNo = {}", channelNo);
				logger.info("Decoder.onImageControlResponsePacket case EB: preset = {}", preset);
			} catch (IOException e) {
				logger.error("Decoder.onImageControlResponsePacket case EB: Data Input Stream Read Error");
				return;
			}

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("commandStatus", commandStatus);
			params.put("requestSetFlag", requestSetFlag);
			params.put("requestFlag", requestFlag);
			params.put("colorSelect", colorSelect);
			params.put("resolution", resolution);
			params.put("luminance", luminance);
			params.put("contrast", contrast);
			params.put("saturation", saturation);
			params.put("channelNo", channelNo);
			params.put("preset", preset);

			Const.getService().execute("POST", prefix + "/imageParam", params);
		}
			break;
		case 0xEC:
		// 收到短视频参数响应 08H-ECH
		{
			int commandStatus, requestSetFlag, channelNo, videoFormat, videoTime;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// commandStatus 1 数据发送状态 FFH成功 00H失败
				// requestSetFlag 1 参数配置类型标识 00H查询 01H设置
				// channelNo 1 通道号
				// videoFormat 1 视频类型
				// videoTime 2 视频录制时间

				commandStatus = input.readUnsignedByte();
				requestSetFlag = input.readUnsignedByte();
				channelNo = input.readUnsignedByte();
				videoFormat = input.readUnsignedByte();
				videoTime = input.readUnsignedShort();

				input.close();

				logger.info("Decoder.onImageControlResponsePacket case EC: commandStatus = {}", commandStatus);
				logger.info("Decoder.onImageControlResponsePacket case EC: requestSetFlag = {}", requestSetFlag);
				logger.info("Decoder.onImageControlResponsePacket case EC: channelNo = {}", channelNo);
				logger.info("Decoder.onImageControlResponsePacket case EC: videoFormat = {}", videoFormat);
				logger.info("Decoder.onImageControlResponsePacket case EC: videoTime = {}", videoTime);
			} catch (IOException e) {
				logger.error("Decoder.onImageControlResponsePacket case EC: Data Input Stream Read Error");
				return;
			}

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("commandStatus", commandStatus);
			params.put("requestSetFlag", requestSetFlag);
			params.put("channelNo", channelNo);
			params.put("videoFormat", videoFormat);
			params.put("videoTime", videoTime);

			Const.getService().execute("POST", prefix + "/videoParam", params);
		}
			break;
		case 0xED:
		// 收到拍照时间响应 08H-EDH
		{
			int commandStatus, requestSetFlag, channelNo;
			int hour1, minute1, hour2, minute2, hour3, minute3;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// commandStatus 1 数据发送状态 FFH成功 00H失败
				// requestSetFlag 1 参数配置类型标识 00H查询配置信息 01H设置配置信息
				// channelNo 1 通道号
				// hour1 1 设备拍照时间间隔小时设置
				// minute1 1 设备拍照时间间隔分钟设置
				// hour2 1 设备开始工作时间小时设置
				// minute2 1 设备开始工作分钟设置
				// hour3 1 设备结束工作时间小时设置
				// minute3 1 设备结束工作时间分钟设置

				commandStatus = input.readUnsignedByte();
				requestSetFlag = input.readUnsignedByte();
				channelNo = input.readUnsignedByte();
				hour1 = input.readUnsignedByte();
				minute1 = input.readUnsignedByte();
				hour2 = input.readUnsignedByte();
				minute2 = input.readUnsignedByte();
				hour3 = input.readUnsignedByte();
				minute3 = input.readUnsignedByte();

				input.close();

				logger.info("Decoder.onImageControlResponsePacket case ED: commandStatus = {}", commandStatus);
				logger.info("Decoder.onImageControlResponsePacket case ED: requestSetFlag = {}", requestSetFlag);
				logger.info("Decoder.onImageControlResponsePacket case ED: channelNo = {}", channelNo);
				logger.info("Decoder.onImageControlResponsePacket case ED: hour1 = {}", hour1);
				logger.info("Decoder.onImageControlResponsePacket case ED: minute1 = {}", minute1);
				logger.info("Decoder.onImageControlResponsePacket case ED: hour2 = {}", hour2);
				logger.info("Decoder.onImageControlResponsePacket case ED: minute2 = {}", minute2);
				logger.info("Decoder.onImageControlResponsePacket case ED: hour3 = {}", hour3);
				logger.info("Decoder.onImageControlResponsePacket case ED: minute3 = {}", minute3);
			} catch (IOException e) {
				logger.error("Decoder.onImageControlResponsePacket case ED: Data Input Stream Read Error");
				return;
			}

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("commandStatus", commandStatus);
			params.put("requestSetFlag", requestSetFlag);
			params.put("channelNo", channelNo);
			params.put("hour1", hour1);
			params.put("minute1", minute1);
			params.put("hour2", hour2);
			params.put("minute2", minute2);
			params.put("hour3", hour3);
			params.put("minute3", minute3);

			Const.getService().execute("POST", prefix + "/shootTime", params);
		}
			break;
		case 0xEE:
		// 收到手动请求拍摄图像/短视频响应 08H-EEH
		{
			int commandStatus;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// commandStatus 1 数据发送状态 FFH成功 00H失败

				commandStatus = input.readUnsignedByte();
				input.close();

				logger.info("Decoder.onImageControlResponsePacket case EE: commandStatus = {}", commandStatus);
			} catch (IOException e) {
				logger.error("Decoder.onImageControlResponsePacket case EE: Data Input Stream Read Error");
				return;
			}

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("commandStatus", commandStatus);

			Const.getService().execute("POST", prefix + "/shootRequest", params);
		}
			break;
		case 0xF3:
		// 接收图像OSD响应 08H-F3H
		{
			int commandStatus, showTime, showText;
			byte[] textContent, reserve;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// commandStatus 1 数据发送状态 FFH成功 00H失败
				// showTime 1 是否显示时间标识 0不显示 1显示
				// showText 1 文本显示标识 0不显示 1显示
				// textContent N 文本内容，UTF-8编码格式，以'\0'结尾
				// reserve 10 备用

				commandStatus = input.readUnsignedByte();
				showTime = input.readUnsignedByte();
				showText = input.readUnsignedByte();
				textContent = readNBytes(input, packet.inApdu.elements.length - 13);
				reserve = readNBytes(input, 10);

				input.close();

				logger.info("Decoder.onImageControlResponsePacket case F3: commandStatus = {}", commandStatus);
				logger.info("Decoder.onImageControlResponsePacket case F3: showTime = {}", showTime);
				logger.info("Decoder.onImageControlResponsePacket case F3: showText = {}", showText);
				logger.info("Decoder.onImageControlResponsePacket case F3: textContent = {}", textContent);
				logger.info("Decoder.onImageControlResponsePacket case F3: reserve = {}", reserve);
			} catch (IOException e) {
				logger.error("Decoder.onImageControlResponsePacket case F3: Data Input Stream Read Error");
				return;
			}

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("commandStatus", commandStatus);
			params.put("showTime", showTime);
			params.put("showText", showText);
			params.put("textContent", textContent);
			params.put("reserve", reserve);

			Const.getService().execute("POST", prefix + "/imageOsd", params);
		}
			break;
		case 0xF5:
		// 接收图像分析参数设置响应 08H-F5H
		{
			int channelNo, preset, analysisFlag, alarmNum, alarmAreaNum;
			int[] alarmTypes, alarmThresholds, areaFlags, areaPointNums;
			int[][] areaPointXs, areaPointYs;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// channelNo 1 通道号
				// preset 1 预置位号
				// analysisFlag 1 智能分析启用标志
				// alarmNum 1 告警类型数量
				// alarmType_i 1 告警i类型
				// alarmThreshold_i 1 告警i阈值
				// alarmAreaNum 1 告警区域数量
				// areaFlag_j 1 区域j作用标志
				// areaPointNum_j 1 区域j坐标点数目
				// areaPointX_j_k 1 区域j坐标点k横坐标
				// areaPointY_j_k 1 区域j坐标点k纵坐标

				channelNo = input.readUnsignedByte();
				preset = input.readUnsignedByte();
				analysisFlag = input.readUnsignedByte();
				alarmNum = input.readUnsignedByte();
				alarmTypes = new int[alarmNum];
				alarmThresholds = new int[alarmNum];
				for (int i = 0; i < alarmNum; i++) {
					alarmTypes[i] = input.readByte();
					alarmThresholds[i] = input.readByte();
				}
				alarmAreaNum = input.readUnsignedByte();
				areaFlags = new int[alarmAreaNum];
				areaPointNums = new int[alarmAreaNum];
				areaPointXs = new int[alarmAreaNum][];
				areaPointYs = new int[alarmAreaNum][];
				for (int j = 0; j < alarmAreaNum; j++) {
					areaFlags[j] = input.readUnsignedByte();
					int pointNum = input.readUnsignedByte();
					areaPointNums[j] = pointNum;
					for (int k = 0; k < pointNum; k++) {
						areaPointXs[j][k] = input.readUnsignedByte();
						areaPointYs[j][k] = input.readUnsignedByte();
					}
				}

				input.close();

				logger.info("Decoder.onImageControlResponsePacket case F5: channelNo = {}", channelNo);
				logger.info("Decoder.onImageControlResponsePacket case F5: preset = {}", preset);
				logger.info("Decoder.onImageControlResponsePacket case F5: analysisFlag = {}", analysisFlag);
				logger.info("Decoder.onImageControlResponsePacket case F5: alarmNum = {}", alarmNum);
				logger.info("Decoder.onImageControlResponsePacket case F5: alarmTypes = {}", alarmTypes.toString());
				logger.info("Decoder.onImageControlResponsePacket case F5: alarmThresholds = {}",
						alarmThresholds.toString());
				logger.info("Decoder.onImageControlResponsePacket case F5: alarmAreaNum = {}", alarmAreaNum);
				logger.info("Decoder.onImageControlResponsePacket case F5: areaFlags = {}", areaFlags.toString());
				logger.info("Decoder.onImageControlResponsePacket case F5: areaPointNums = {}",
						areaPointNums.toString());
				logger.info("Decoder.onImageControlResponsePacket case F5: areaPointXs = {}", areaPointXs.toString());
				logger.info("Decoder.onImageControlResponsePacket case F5: areaPointYs = {}", areaPointYs.toString());
			} catch (IOException e) {
				logger.error("Decoder.onImageControlResponsePacket case F5: Data Input Stream Read Error");
				return;
			}

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("channelNo", channelNo);
			params.put("preset", preset);
			params.put("analysisFlag", analysisFlag);
			params.put("alarmNum", alarmNum);
			params.put("alarmTypes", alarmTypes);
			params.put("alarmThresholds", alarmThresholds);
			params.put("alarmAreaNum", alarmAreaNum);
			params.put("areaFlags", areaFlags);
			params.put("areaPointNums", areaPointNums);
			params.put("areaPointXs", areaPointXs);
			params.put("areaPointYs", areaPointYs);

			Const.getService().execute("POST", prefix + "/imageAnalysisParamSet", params);
		}
			break;
		case 0xF6:
		// 接收图像分析参数查询响应 08H-F6H
		{
			int channelNo, preset, analysisFlag, alarmNum, alarmAreaNum;
			int[] alarmTypes, alarmThresholds, areaFlags, areaPointNums;
			int[][] areaPointXs, areaPointYs;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// channelNo 1 通道号
				// preset 1 预置位号
				// analysisFlag 1 智能分析启用标志
				// alarmNum 1 告警类型数量
				// alarmType_i 1 告警i类型
				// alarmThreshold_i 1 告警i阈值
				// alarmAreaNum 1 告警区域数量
				// areaFlag_j 1 区域j作用标志
				// areaPointNum_j 1 区域j坐标点数目
				// areaPointX_j_k 1 区域j坐标点k横坐标
				// areaPointY_j_k 1 区域j坐标点k纵坐标

				channelNo = input.readUnsignedByte();
				preset = input.readUnsignedByte();
				analysisFlag = input.readUnsignedByte();
				alarmNum = input.readUnsignedByte();
				alarmTypes = new int[alarmNum];
				alarmThresholds = new int[alarmNum];
				for (int i = 0; i < alarmNum; i++) {
					alarmTypes[i] = input.readByte();
					alarmThresholds[i] = input.readByte();
				}
				alarmAreaNum = input.readUnsignedByte();
				areaFlags = new int[alarmAreaNum];
				areaPointNums = new int[alarmAreaNum];
				areaPointXs = new int[alarmAreaNum][];
				areaPointYs = new int[alarmAreaNum][];
				for (int j = 0; j < alarmAreaNum; j++) {
					areaFlags[j] = input.readUnsignedByte();
					int pointNum = input.readUnsignedByte();
					areaPointNums[j] = pointNum;
					for (int k = 0; k < pointNum; k++) {
						areaPointXs[j][k] = input.readUnsignedByte();
						areaPointYs[j][k] = input.readUnsignedByte();
					}
				}

				input.close();

				logger.info("Decoder.onImageControlResponsePacket case F6: channelNo = {}", channelNo);
				logger.info("Decoder.onImageControlResponsePacket case F6: preset = {}", preset);
				logger.info("Decoder.onImageControlResponsePacket case F6: analysisFlag = {}", analysisFlag);
				logger.info("Decoder.onImageControlResponsePacket case F6: alarmNum = {}", alarmNum);
				logger.info("Decoder.onImageControlResponsePacket case F6: alarmTypes = {}", alarmTypes.toString());
				logger.info("Decoder.onImageControlResponsePacket case F6: alarmThresholds = {}",
						alarmThresholds.toString());
				logger.info("Decoder.onImageControlResponsePacket case F6: alarmAreaNum = {}", alarmAreaNum);
				logger.info("Decoder.onImageControlResponsePacket case F6: areaFlags = {}", areaFlags.toString());
				logger.info("Decoder.onImageControlResponsePacket case F6: areaPointNums = {}",
						areaPointNums.toString());
				logger.info("Decoder.onImageControlResponsePacket case F6: areaPointXs = {}", areaPointXs.toString());
				logger.info("Decoder.onImageControlResponsePacket case F6: areaPointYs = {}", areaPointYs.toString());
			} catch (IOException e) {
				logger.error("Decoder.onImageControlResponsePacket case F6: Data Input Stream Read Error");
				return;
			}

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("channelNo", channelNo);
			params.put("preset", preset);
			params.put("analysisFlag", analysisFlag);
			params.put("alarmNum", alarmNum);
			params.put("alarmTypes", alarmTypes);
			params.put("alarmThresholds", alarmThresholds);
			params.put("alarmAreaNum", alarmAreaNum);
			params.put("areaFlags", areaFlags);
			params.put("areaPointNums", areaPointNums);
			params.put("areaPointXs", areaPointXs);
			params.put("areaPointYs", areaPointYs);

			Const.getService().execute("POST", prefix + "/imageAnalysisParamGet", params);
		}
			break;
		default:
			logger.error("Decoder.onImageControlResponsePacket: Unknown msgType {}", packet.inApdu.msgType);
			break;
		}
	}

	// 工作状态响应报 客户端使用
	// 接收 0AH
	// 发送 09H
	public static void onWorkStateResponsePacket(MonitorPacket packet, ChannelContext context) {
		switch (packet.inApdu.msgType) {
		case 0xFA: // 响应基本信息查询
		{
			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			// setFlag 1 标识位，00H查询

			int setFlag;
			try {
				setFlag = input.readUnsignedByte();
			} catch (IOException e) {
				logger.error("Decoder.onWorkStateResponseData case 0xFA: Data Input Stream Read Error");
				return;
			}

			if (setFlag == 0x00) {
				String deviceId = packet.identification;
				sendPacket(deviceId, context, Encoder.makeAdditionalBasicInfoGetPacket(deviceId));
			}
		}
			break;
		case 0xFB: // 响应工作状态查询
		{
			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			// setFlag 1 标识位 00H查询

			int setFlag;
			try {
				setFlag = input.readByte();
			} catch (IOException e) {
				logger.error("Decoder.onWorkStateResponseData case 0xFB: Data Input Stream Read Error");
				return;
			}

			if (setFlag == 0x00) {
				String deviceId = packet.identification;
				sendPacket(deviceId, context, Encoder.makeAdditionalBasicInfoGetPacket(deviceId));
			}
		}
			break;
		default:
			logger.error("Decoder.onWorkStateResponseData: Unknown msgType {}", packet.inApdu.msgType);
			break;
		}
	}

	// 服务端使用
	// 收到工作状态报 09H
	// 发送工作状态响应报 0AH
	public static void onWorkStatePacket(MonitorPacket packet, ChannelContext context) {
		switch (packet.inApdu.msgType) {
		case 0xE6:
		// 接收心跳数据报文 09H-E6H
		// 响应 0AH-E6H
		{
			int clockTimeStamp;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// clockTimeStamp 4 当前时间

				clockTimeStamp = input.readInt();
				input.close();

				logger.info("Decoder.onWorkStatePacket case E6: clocktimeStamp = {}", clockTimeStamp);
			} catch (IOException e) {
				logger.error("Decoder.onWorkStatePacket case E6: Data Input Stream Read Error");
				return;
			}

			int msgLen = 4;
			ByteArrayOutputStream byteStream = new ByteArrayOutputStream(msgLen);
			LittleEndianDataOutputStream output = new LittleEndianDataOutputStream(byteStream);

			try {
				// clocktimeStamp 4 当前时间

				output.writeInt((int) (System.currentTimeMillis() / 1000));
				output.close();
			} catch (IOException e) {
				logger.error("Decoder.onWorkStatePacket case E6: Data Output Stream Write Error");
				return;
			}

			packet.outApduQueue.offer(new Apdu(0x0A, 0xE6, msgLen, byteStream.toByteArray()));
			sendPacket(packet.identification, context, packet);

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("clockTimeStamp", clockTimeStamp);
			Const.getService().execute("POST", prefix + "/heartbeat", params);
		}
			break;
		case 0xE7:
		// 接收监测装置基本信息数据 09H-E7H
		// 响应 0AH-E7H
		{
			byte[] smartEquipName, model, dataTransProtocolVersion, essentialInfoVersion, bsManufacturer,
					bsProductionDate, bsIdentifier;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// smartEquipName 50 监测装置名称
				// model 10 监测装置型号
				// dataTransProtocolVersion 4 监测装置遵循的应用层数据传输规约版本号
				// essentialInfoVersion 4 监测装置基本信息版本号
				// bsManufacturer 50 生产厂家
				// bsProductionDate 4 生产日期
				// bsIdentifier 20 出厂编号

				smartEquipName = readNBytes(input, 50);
				model = readNBytes(input, 10);
				dataTransProtocolVersion = readNBytes(input, 4);
				essentialInfoVersion = readNBytes(input, 4);
				bsManufacturer = readNBytes(input, 50);
				bsProductionDate = readNBytes(input, 4);
				bsIdentifier = readNBytes(input, 20);

				input.close();

				logger.info("Decoder.onWorkStatePacket case E7: smartEquipName = {}", smartEquipName.toString());
				logger.info("Decoder.onWorkStatePacket case E7: model = {}", model.toString());
				logger.info("Decoder.onWorkStatePacket case E7: dataTransProtocolVersion = {}",
						dataTransProtocolVersion.toString());
				logger.info("Decoder.onWorkStatePacket case E7: essentialInfoVersion = {}",
						essentialInfoVersion.toString());
				logger.info("Decoder.onWorkStatePacket case E7: bsManufacturer = {}", bsManufacturer.toString());
				logger.info("Decoder.onWorkStatePacket case E7: bsProductionDate = {}", bsProductionDate.toString());
				logger.info("Decoder.onWorkStatePacket case E7: bsIdentifier = {}", bsIdentifier.toString());
			} catch (IOException e) {
				logger.error("Decoder.onWorkStatePacket case E7: Data Input Stream Read Error");
				return;
			}

			// commandStatus 1 数据发送状态 FFH成功 00H失败
			// RegisterFlag 1 注册标识信息 00H注册成功 01H注册失败

			packet.outApduQueue.offer(new Apdu(0x0A, 0xE7, 2, new byte[] { (byte) 0xFF, 0x00 }));
			sendPacket(packet.identification, context, packet);

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("smartEquipName", smartEquipName);
			params.put("model", model);
			params.put("dataTransProtocolVersion", dataTransProtocolVersion);
			params.put("essentialInfoVersion", essentialInfoVersion);
			params.put("bsManufacturer", bsManufacturer);
			params.put("bsProductionDate", bsProductionDate);
			params.put("bsIdentifier", bsIdentifier);

			Const.getService().execute("POST", prefix + "/basicInfo", params);
		}
			break;
		case 0xE8:
		// 接收监测装置工作状态报文 09H-E8H
		// 响应 0AH-E8H
		{
			int timeStamp;
			float batteryVoltage, operationTemperature, batteryCapacity;
			int floatingCharge, totalWorkingTime, workingTime, connectionState;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// timeStamp 4 采集时间
				// batteryVoltage 4 电源电压 浮点型
				// operationTemperature 4 工作温度 浮点型
				// batteryCapacity 4 电池电量 浮点型
				// floatingCharge 1 浮充状态 00H充电 01H放电
				// totalWorkingTime 4 工作总时间
				// workingTime 4 本次连续工作时间
				// connectionState 1 网络连接状态 00H正常 01H断开

				timeStamp = input.readInt();
				batteryVoltage = input.readFloat();
				operationTemperature = input.readFloat();
				batteryCapacity = input.readFloat();
				floatingCharge = input.readByte();
				totalWorkingTime = input.readInt();
				workingTime = input.readInt();
				connectionState = input.readByte();

				input.close();

				logger.info("Decoder.onWorkStatePacket case E8: timeStamp = {}", timeStamp);
				logger.info("Decoder.onWorkStatePacket case E8: batteryVoltage = {}", batteryVoltage);
				logger.info("Decoder.onWorkStatePacket case E8: operationTemperature = {}", operationTemperature);
				logger.info("Decoder.onWorkStatePacket case E8: batteryCapacity = {}", batteryCapacity);
				logger.info("Decoder.onWorkStatePacket case E8: floatingCharge = {}", floatingCharge);
				logger.info("Decoder.onWorkStatePacket case E8: totalWorkingTime = {}", totalWorkingTime);
				logger.info("Decoder.onWorkStatePacket case E8: workingTime = {}", workingTime);
				logger.info("Decoder.onWorkStatePacket case E8: connectionState = {}", connectionState);
			} catch (IOException e) {
				logger.error("Decoder.onWorkStatePacket case E8: Data Input Stream Read Error");
				return;
			}

			// commandStatus 1 数据发送状态 FFH成功 00H失败

			packet.outApduQueue.offer(new Apdu(0x0A, 0xE8, 1, new byte[] { (byte) 0xFF }));
			sendPacket(packet.identification, context, packet);

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("timeStamp", timeStamp);
			params.put("batteryVoltage", batteryVoltage);
			params.put("operationTemperature", operationTemperature);
			params.put("batteryCapacity", batteryCapacity);
			params.put("floatingCharge", floatingCharge);
			params.put("totalWorkingTime", totalWorkingTime);
			params.put("workingTime", workingTime);
			params.put("connectionState", connectionState);
			Const.getService().execute("POST", prefix + "/workState", params);
		}
			break;
		case 0xE9:
		// 接收故障信息报文 09H-E9H
		// 响应 0AH-E9H
		{
			int timeStamp;
			String faultDesc;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// timeStamp 4 采集时间
				// faultDesc N 检测装置故障描述信息

				timeStamp = input.readInt();
				faultDesc = new String(readNBytes(input, packet.inApdu.elements.length - 4));

				input.close();

				logger.info("Decoder.onWorkStatePacket case E9: timeStamp = {}", timeStamp);
				logger.info("Decoder.onWorkStatePacket case E9: faultDesc = {}", faultDesc);
			} catch (IOException e) {
				logger.error("Decoder.onWorkStatePacket case E9: Data Input Stream Read Error");
				return;
			}

			// commandStatus 1 数据发送状态 FFH成功 00H失败

			packet.outApduQueue.offer(new Apdu(0x0A, 0xE9, 1, new byte[] { (byte) 0xFF }));
			sendPacket(packet.identification, context, packet);

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("timeStamp", timeStamp);
			params.put("faultDesc", faultDesc);
			Const.getService().execute("POST", prefix + "/faultDesc", params);
		}
			break;
		case 0xFA:
		// 接收监测装置基本信息补充报文
		{
			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			int commandStatus;
			byte[] function, aiFunction;
			int channelGroup;
			byte[] channelNos, channelFuns, iccid;
			int operator;
			byte[] protocolVersion, factoryFlag, systemVersion, reserve;

			try {
				// commandStatus 1 数据发送状态
				// function 8 功能类型
				// aiFunction 4 智能分析功能类型
				// channelGroup 1 通道数
				// channelNo_i 1 通道号
				// channelFun_i 1 通道功能
				// iccid 25 卡信息
				// operator 1 运营商
				// protocolVersion 32 协议版本号
				// factoryFlag 8 厂家标识
				// systemVersion N 系统版本号
				// reserve 20 备用

				commandStatus = input.readUnsignedByte();
				function = readNBytes(input, 8);
				aiFunction = readNBytes(input, 4);
				channelGroup = input.readByte();
				channelNos = new byte[channelGroup];
				channelFuns = new byte[channelGroup];
				for (int i = 0; i < channelGroup; i++) {
					channelNos[i] = input.readByte();
					channelFuns[i] = input.readByte();
				}
				iccid = readNBytes(input, 25);
				operator = input.readUnsignedByte();
				protocolVersion = readNBytes(input, 32);
				factoryFlag = readNBytes(input, 8);
				systemVersion = readNBytes(input, channelGroup);
				reserve = readNBytes(input, 20);

				input.close();

				logger.info("Decoder.onWorkStatePacket case FA: commandStatus = {}", commandStatus);
				logger.info("Decoder.onWorkStatePacket case FA: function = {}", function.toString());
				logger.info("Decoder.onWorkStatePacket case FA: aiFunction = {}", aiFunction.toString());
				logger.info("Decoder.onWorkStatePacket case FA: channelGroup = {}", channelGroup);
				logger.info("Decoder.onWorkStatePacket case FA: channelNo = {}", channelNos.toString());
				logger.info("Decoder.onWorkStatePacket case FA: channelFuns = {}", channelFuns.toString());
				logger.info("Decoder.onWorkStatePacket case FA: iccid = {}", iccid.toString());
				logger.info("Decoder.onWorkStatePacket case FA: operator = {}", operator);
				logger.info("Decoder.onWorkStatePacket case FA: protocolVersion = {}", protocolVersion.toString());
				logger.info("Decoder.onWorkStatePacket case FA: factoryFlag = {}", factoryFlag.toString());
				logger.info("Decoder.onWorkStatePacket case FA: systemVersion = {}", systemVersion.toString());
				logger.info("Decoder.onWorkStatePacket case FA: reserve = {}", reserve.toString());
			} catch (IOException e) {
				logger.error("Decoder.onWorkStatePacket case 0xFA: Data Input Stream Read Error");
				return;
			}

			// commandStatus 1 数据发送状态 FFH成功 00H失败

			packet.outApduQueue.offer(new Apdu(0x0A, 0xFA, 1, new byte[] { (byte) 0xFF }));
			sendPacket(packet.identification, context, packet);

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("commandStatus", commandStatus);
			params.put("functionType", function.toString());
			params.put("aiFunction", aiFunction.toString());
			params.put("channelGroup", channelGroup);
			params.put("channelNos", channelNos.toString());
			params.put("channelFuns", channelFuns.toString());
			params.put("iccid", iccid.toString());
			params.put("operator", operator);
			params.put("protocolVersion", protocolVersion.toString());
			params.put("factoryFlag", factoryFlag.toString());
			params.put("systemVersion", systemVersion.toString());
			params.put("reserve", reserve.toString());
			Const.getService().execute("POST", prefix + "/additionalBasicInfo", params);
		}
			break;
		case 0xFB: // 接收监测装置工作状态补充报文
		{
			int commandStatus, signalStrength, dbm, dbmMin, dbmMax;
			float dayNetflow, monthNetflow;
			byte[] function, reserve;

			LittleEndianDataInputStream input = new LittleEndianDataInputStream(
					new ByteArrayInputStream(packet.inApdu.elements));

			try {
				// commandStatus 1 数据发送状态
				// SignalStrength 1 信号等级
				// dbm 2 信号强度实测值
				// dbmMin 2 DBM下限
				// dbmMax 2 DBM上限
				// dayNetflow 4 当日已用流量
				// MonthNetflow 4 当月已用流量
				// function 8 功能类型
				// reserve 20 备用

				commandStatus = input.readUnsignedByte();
				signalStrength = input.readUnsignedByte();
				dbm = input.readUnsignedShort();
				dbmMin = input.readUnsignedShort();
				dbmMax = input.readUnsignedShort();
				dayNetflow = input.readFloat();
				monthNetflow = input.readFloat();
				function = readNBytes(input, 8);
				reserve = readNBytes(input, 20);

				input.close();

				logger.info("Decoder.onWorkStatePacket case FB: commandStatus = {}", commandStatus);
				logger.info("Decoder.onWorkStatePacket case FB: signalStrength = {}", signalStrength);
				logger.info("Decoder.onWorkStatePacket case FB: dbm = {}", dbm);
				logger.info("Decoder.onWorkStatePacket case FB: dbmMin = {}", dbmMin);
				logger.info("Decoder.onWorkStatePacket case FB: dbmMax = {}", dbmMax);
				logger.info("Decoder.onWorkStatePacket case FB: dayNetflow = {}", dayNetflow);
				logger.info("Decoder.onWorkStatePacket case FB: monthNetflow = {}", monthNetflow);
				logger.info("Decoder.onWorkStatePacket case FB: function = {}", function.toString());
				logger.info("Decoder.onWorkStatePacket case FB: reserve = {}", reserve.toString());
			} catch (IOException e) {
				logger.error("Decoder.onWorkStatePacket case 0xFB: Data Input Stream Read Error");
				return;
			}

			// commandStatus 1 数据发送状态 FFH成功 00H失败

			packet.outApduQueue.offer(new Apdu(0x0A, 0xFB, 1, new byte[] { (byte) 0xFF }));
			sendPacket(packet.identification, context, packet);

			Map<String, Object> params = new HashMap<>();
			params.put("deviceId", packet.identification);
			params.put("commandStatus", commandStatus);
			params.put("signalStrength", signalStrength);
			params.put("dbm", dbm);
			params.put("dbmMin", dbmMin);
			params.put("dbmMax", dbmMax);
			params.put("dayNetflow", dayNetflow);
			params.put("monthNetflow", monthNetflow);
			params.put("functionType", function.toString());
			params.put("reserve", reserve.toString());
			Const.getService().execute("POST", prefix + "/additionalWorkState", params);
		}
			break;
		default:
			logger.error("Decoder.onWorkStatePacket: Unknown msgType {}", packet.inApdu.msgType);
			break;
		}

	}
}